// J2ME Compass
// Copyright (C) 2006 Dana Peters
// http://www.qcontinuum.org/compass

package org.qcontinuum.astro;

import henson.midp.Float;
import java.util.*;

public class UtcDate {
    
    final static private Float c86400 = new Float(86400);
    final static private Float c51544_5 = new Float(515445, -1);
    final static private Float c36525 = new Float(36525);
    final static private Float c24110_54841 = new Float(2411054841L, -5);
    final static private Float c8640184_812866 = new Float(8640184812866L, -6);
    final static private Float c1_0027379093 = new Float(10027379093L, -10);
    final static private Float c0_093104 = new Float(93104, -6);
    final static private Float c0_0000062 = new Float(62, -7);

    private int mYear, mMonth, mDay, mHour, mMinute, mSecond;

    public UtcDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeZone(TimeZone.getDefault());
        cal.setTime(date);
        mYear = cal.get(Calendar.YEAR);
        mMonth = cal.get(Calendar.MONTH) + 1;
        mDay = cal.get(Calendar.DAY_OF_MONTH);
        mHour = cal.get(Calendar.HOUR_OF_DAY);
        mMinute = cal.get(Calendar.MINUTE);
        mSecond = cal.get(Calendar.SECOND);
    }

    public UtcDate(int year, int month, int day, int hour, int minute, int second) {
        mYear = year;
        mMonth = month;
        mDay = day;
        mHour = hour;
        mMinute = minute;
        mSecond = second;
    }
            
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append(mYear);
        sb.append('-');
        sb.append(mMonth);
        sb.append('-');
        sb.append(mDay);
        sb.append(' ');
        sb.append(mHour);
        sb.append(':');
        if (mMinute < 10)
            sb.append('0');
        sb.append(mMinute);
        sb.append(':');
        if (mSecond < 10)
            sb.append('0');
        sb.append(mSecond);
        return sb.toString();
    }

    public String getDateString() {
        StringBuffer sb = new StringBuffer();
        sb.append(mYear);
        sb.append('-');
        sb.append(mMonth);
        sb.append('-');
        sb.append(mDay);
        return sb.toString();
    }
    
    public String getTimeString() {
        StringBuffer sb = new StringBuffer();
        sb.append(mHour);
        sb.append(':');
        if (mMinute < 10)
            sb.append('0');
        sb.append(mMinute);
        sb.append(':');
        if (mSecond < 10)
            sb.append('0');
        sb.append(mSecond);
        return sb.toString();
    }

    // Modified Julian Date
    public Float getMJD() {
        if (mMonth <= 2) {
            mMonth  += 12;
            --mYear;
        }
        int b = (mYear / 400) - (mYear / 100) + (mYear / 4);  // Gregorian calendar
        long MjdMidnight = 365L * mYear - 679004L + b + ((306001L * (mMonth + 1)) / 10000L) + mDay;
        //FracOfDay   = (Hour + Min/60.0) / 24.0;
        Float FracOfDay = (new Float(mHour).Add(new Float(mMinute).Div(60))).Div(24);
        return new Float(MjdMidnight).Add(FracOfDay);
    }
 
    // Greenwich Mean Sidereal Time
    public static Float GMST(Float MJD)
    {
        Float MJD_0 = Float.floor(MJD);
        // UT    = Secs * (MJD - MJD_0);
        Float UT = c86400.Mul(MJD.Sub(MJD_0));
        // T_0 = (MJD_0 - 51544.5) / 36525.0; 
        Float T_0 = MJD_0.Sub(c51544_5).Div(c36525); 
        // T  = (MJD - 51544.5) / 36525.0; 
        Float T  = MJD.Sub(c51544_5).Div(c36525); 
        // gmst  = 24110.54841 + 8640184.812866 * T_0 + 1.0027379093 * UT 
        //         + (0.093104 - 6.2e-6 * T) * T * T;
        Float gmst = c24110_54841.Add(c8640184_812866.Mul(T_0)).Add(c1_0027379093.Mul(UT))
            .Add(c0_093104.Sub(c0_0000062.Mul(T)).Mul(T).Mul(T));
        // return (pi2 / Secs) * Modulo(gmst, Secs);   // [Rad]
        return Float.PImul2.Div(c86400).Mul(Modulo(gmst, c86400));
    }
    
    private static Float Modulo(Float x, Float y)
    {
        return y.Mul(Float.Frac(x.Div(y)));
    }
}
